#include <netfwd.h>
#include <netsocket.h>
#include <udpsession.h>
#include <udptransmit.h>
#include <udpeventmonitor.h>
#include <netglobal.h>
#include <logger.h>
#include <netreactor.h>

class UDPServer : public UDPEventMonitor
{
public:
	virtual ~UDPServer() throw() {
		LOG_STREAM_DEBUG << "UDPServer destruct" << LOG_EOM;
	}

    virtual int32_t on_connect( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "client[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] connected" << LOG_EOM;
		return 0;
	}

    virtual int32_t on_read( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "client[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] can read!" << LOG_EOM;

		char buf[4096] = {0};
		int32_t size = udp_session->read_package( buf, 4094 );

        int32_t file = ::open( "server_recv.txt", O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR );
        ::write( file, buf, size );
        ::close( file );
		return 0;
	}

    virtual int32_t on_disconnect( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "client[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] disconnected" << LOG_EOM;
		udp_session->get_udp_transmit()->release_session( udp_session );
		return 0;
	}

    virtual int32_t on_connect_failed( UDPSession * udp_session )
	{
		return 0;
	}
};

class UDPClient : public UDPEventMonitor
{
public:
	virtual ~UDPClient() throw() {
		LOG_STREAM_DEBUG << "UDPClient destruct" << LOG_EOM;
	}

    virtual int32_t on_connect( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "connect to server[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] connect successed" << LOG_EOM;

		char buf[4096];
        memset( buf, '1', 4090 );
		udp_session->send_package( buf, 4090 );
		return 0;
	}

    virtual int32_t on_read( UDPSession * udp_session )
	{
		return 0;
	}

    virtual int32_t on_disconnect( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "client to server[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] disconnect, now reconnect...." << LOG_EOM;
		//udp_session->get_udp_transmit()->release_session( udp_session );
		udp_session->connect();
		return 0;
	}

    virtual int32_t on_connect_failed( UDPSession * udp_session )
	{
		LOG_STREAM_DEBUG << "client to server[" << udp_session->get_ipname()
						 << ":" << udp_session->get_port()
						 << "] failed" << LOG_EOM;
		udp_session->get_udp_transmit()->release_session( udp_session );
        NetGlobal::net_reactor().shutdown();
		return 0;
	}
};

static void signal_handler( int32_t sig )
{
	switch( sig )
	{
	case SIGINT:
		{
			fprintf( stderr, "catch signal SIGINT, server is shutdown\n" );
			NetGlobal::net_reactor().shutdown();
			break;
		}
	}
	return;
}

int32_t main( int32_t argc, char* argv[] )
{
	int32_t 	app_type = 0;
	char 		local_ip[IPBUF_LEN];
	int32_t		local_port;
	char		remote_ip[IPBUF_LEN];
	int32_t		remote_port;

	if( 1 == argc )
	{
		fprintf( stderr, "./test server ip port[client ip port remote_ip remote_port] \n" );
		return -1;
	}

	std::string log_file;
	if( 0 == strcmp( argv[1], "server" ) )
	{
		log_file = "test_server";
		app_type = 1;
		strcpy( local_ip, argv[2] );
		local_port = strtol( argv[3], 0, 10 );
	}
	else if( 0 == strcmp( argv[1], "client" ) )
	{
		log_file = "test_client";
		app_type = 0;
		strcpy( local_ip, argv[2] );
		local_port = strtol( argv[3], 0, 10 );
		strcpy( remote_ip, argv[4] );
		remote_port = strtol( argv[5], 0, 10 );
	}
	else {
		fprintf( stderr, "./test server ip port[client ip port remote_ip remote_port] \n" );
		return -1;
	}

	struct sigaction act;

	act.sa_handler = SIG_IGN;
	sigaction( SIGTERM, &act, NULL );
	sigaction( SIGPIPE, &act, NULL );
	sigaction( SIGHUP,  &act, NULL );
	sigaction( SIGCHLD, &act, NULL );
	sigaction( SIGALRM, &act, NULL );

	act.sa_handler = signal_handler;
	sigemptyset( &act.sa_mask );
	act.sa_flags = 0;
	sigaction( SIGINT, &act, NULL );

	init_dailylog( log_file.c_str(), MsgLogger::ELOGLEVEL_DEBUG );

	NetReactor * reactor = &NetGlobal::net_reactor();
	UDPTransmit * udp_transmit = NULL;
	UDPEventMonitor * udp_monitor = NULL;

	if( 1 == app_type )
	{
		//server
		LOG_STREAM_DEBUG << "UDP SERVER NOW START....." << LOG_EOM;
		udp_monitor = new UDPServer();
		udp_transmit = new UDPTransmit( reactor, udp_monitor );
		udp_transmit->start( local_ip, local_port );
	}
	else
	{
		// client
		LOG_STREAM_DEBUG << "UDP CLIENT NOW START....." << LOG_EOM;
		udp_monitor = new UDPClient();
		udp_transmit = new UDPTransmit( reactor, udp_monitor );
		udp_transmit->start( local_ip, local_port );
		UDPSession * client1 = udp_transmit->create_client_session( remote_ip, remote_port );
		client1->connect();
	}

	NetGlobal::net_reactor().main_loop();

    if( 1 != app_type )
        LOG_STREAM_DEBUG << "connect failed, now exit!!!" << LOG_EOM;

	delete udp_monitor;
	udp_transmit->stop();
	delete udp_transmit;

    sleep( 1 );
	fini_log();
	return 0;
}

